package com.kuaiyin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kuaiyin.dto.TestCaseDTO;
import com.kuaiyin.entity.TestCase;
import com.kuaiyin.enums.BizCodeEnum;
import com.kuaiyin.enums.ExecStatus;
import com.kuaiyin.enums.Status;
import com.kuaiyin.exception.BaseException;
import com.kuaiyin.executor.TestCaseExecutor;
import com.kuaiyin.mapper.RequestMapper;
import com.kuaiyin.mapper.TestCaseMapper;
import com.kuaiyin.mapper.TestPlanCaseMapper;
import com.kuaiyin.service.ITestCaseService;
import com.kuaiyin.utils.PageHelper;
import com.kuaiyin.utils.PageResult;
import com.kuaiyin.utils.RedisUtils;
import com.kuaiyin.vo.TestCaseVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * <p>
 * 测试用例表（assertions可选） 服务实现类
 * </p>
 *
 * @author ng
 * @since 2025-04-27
 */
@Slf4j
@Service
public class TestCaseServiceImpl extends ServiceImpl<TestCaseMapper, TestCase> implements ITestCaseService {


    @Autowired
    private TestCaseMapper testCaseMapper;
    @Autowired
    private RequestMapper requestMapper;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private TestPlanCaseMapper testPlanCaseMapper;


    @Override
    public void savaTestCase(TestCaseDTO testCaseDTO) {
        if (lambdaQuery().eq(TestCase::getName, testCaseDTO.getName()).exists()) {
            throw BaseException.of(BizCodeEnum.TEST_CASE_NAME_DUPLICATED);
        }
        if (requestMapper.selectById(testCaseDTO.getRequestId()) == null) {
            throw BaseException.of(BizCodeEnum.TEST_CASE_REQUEST_NOT_EXIST);
        }
        TestCase testCase = new TestCase();
        BeanUtils.copyProperties(testCaseDTO, testCase);
        testCaseMapper.insert(testCase);
    }

    @Override
    public TestCaseVO getById(Long id) {
        //校验是否存在
        if (!lambdaQuery().eq(TestCase::getId, id).exists()) {
            throw BaseException.of(BizCodeEnum.TEST_CASE_ID_NOT_EXIST);
        }
        TestCase testCase = super.getById(id);
        TestCaseVO testCaseVO = new TestCaseVO();
        BeanUtils.copyProperties(testCase, testCaseVO);
        return testCaseVO;
    }


    @Override
    public void updateTestCase(Long id, TestCaseDTO testCaseDTO) {
        testCaseDTO.setId(id);
        if (lambdaQuery().eq(TestCase::getName, testCaseDTO.getName()).ne(TestCase::getId, id).exists()) {
            throw BaseException.of(BizCodeEnum.TEST_CASE_NAME_EXISTS);
        }
        if (requestMapper.selectById(testCaseDTO.getRequestId()) == null) {
            throw BaseException.of(BizCodeEnum.TEST_CASE_REQUEST_NOT_FOUND);
        }
        TestCase testCase = new TestCase();
        BeanUtils.copyProperties(testCaseDTO, testCase);
        testCaseMapper.updateById(testCase);
    }

    @Override
    public List<TestCaseVO> getTestCaseList() {
        return PageHelper.queryAllWithVo(testCaseMapper, TestCaseVO.class);
    }

    @Override
    public PageResult<TestCaseVO> getTestCasePage(Integer page, Integer size, Consumer<LambdaQueryWrapper<TestCase>> condition) {
        return PageHelper.queryWithVo(page, size, testCaseMapper, TestCaseVO.class, condition);
    }

    @Override
    public void updateTestCaseStatus(Long id, Integer status) {
        //校验id是否被计划关联
        List<Long> planIds = testPlanCaseMapper.selectCasesByPlanIds(id);
        if (planIds != null && !planIds.isEmpty()) {
            String planIdList = planIds.stream().map(String::valueOf).collect(java.util.stream.Collectors.joining(", "));
            throw BaseException.of(0, "该用例被以下计划引用，不能删除：" + planIdList);
        }
        TestCase testCase = new TestCase();
        testCase.setId(id);
        testCase.setStatus(Status.fromCode(status));
        testCaseMapper.updateById(testCase);
    }

    @Override
    public Map<String, String> getCase(Long id) {
        String key = "testCase_id_" + id;
        //校验下缓存是否存在
        if(!redisUtils.exists(key)){
            throw  BaseException.of(0, "该用例的报告不存在，请重新生成！");
        }
        return redisUtils.getHashEntriesAsStringMap(key);
    }


    @Override
    public void removeById(Long id) {
        List<Long> planIds = testPlanCaseMapper.selectCasesByPlanIds(id);
        if (planIds != null && !planIds.isEmpty()) {
            // 提示被哪些计划引用
            String planIdList = planIds.stream()
                    .map(String::valueOf)
                    .collect(java.util.stream.Collectors.joining(", "));
            throw BaseException.of(0, "测试ID-" + id + "被以下计划引用，不能删除：" + planIdList);
        }
        testCaseMapper.deleteById(id);
    }


    @Override
    public void runTestCase(Long id) {
        // 1. 获取基础数据
        TestCase testCase = lambdaQuery().eq(TestCase::getId, id).one(); // 获取测试用例数据
        if (testCase == null || testCase.getStatus() == Status.NORMAL) {
            throw BaseException.of(BizCodeEnum.TEST_CASE_NOT_EXIST_OR_DISABLED);
        }
        // 更新执行状态为 PENDING
        testCase.setExecStatus(String.valueOf(ExecStatus.PENDING));
        testCase.setLastRunTime(LocalDateTime.now());  //  最后一次执行开始时间

        long startTime = System.currentTimeMillis();// 获取当前时间毫秒数

        //2、构建执行器
        TestCaseExecutor executor = new TestCaseExecutor(testCaseMapper, requestMapper, redisUtils, id);
        try {
            executor.execute(id);  //  执行用例
            //  更新执行状态为 SUCCESS
            testCase.setExecStatus(String.valueOf(ExecStatus.SUCCESS));
            testCase.setLastRunResult(String.valueOf(ExecStatus.SUCCESS));
        } catch (BaseException | IOException e) {
            testCase.setExecStatus("FAILED");
            testCase.setLastRunResult("FAILED");
            testCaseMapper.updateById(testCase);
            if (e instanceof BaseException) {
                throw (BaseException) e;
            } else {
                log.error("执行测试用例时发生 IO 异常，ID: {}", id, e); // 推荐添加日志
                throw BaseException.of(0, "执行失败", e);
            }
        }
        long endTime = System.currentTimeMillis();
        testCase.setLastRunDuration((int) (endTime - startTime)); //  耗时
        testCase.setLastRunResult(String.valueOf(ExecStatus.SUCCESS)); //  最后一次执行结果
        testCaseMapper.updateById(testCase);
    }


}
